home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Freeware 2001 May
/
SGI Freeware 2001 May - Disc 3.iso
/
dist
/
fw_elisp-intro.idb
/
usr
/
freeware
/
info
/
emacs-lisp-intro.info-8.z
/
emacs-lisp-intro.info-8
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
GNU Info File
|
1998-10-28
|
45.3 KB
|
1,119 lines
This is Info file emacs-lisp-intro.info, produced by Makeinfo version
1.67 from the input file emacs-lisp-intro.texi.
This is an introduction to `Programming in Emacs Lisp', for people
who are not programmers.
Edition 1.05, 21 October 1997
Copyright (C) 1990, '91, '92, '93, '94, '95, '97 Free Software
Foundation, Inc.
Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.
Permission is granted to copy and distribute modified versions of
this manual under the conditions for verbatim copying, provided also
that the sections entitled "Copying" and "GNU General Public License"
are included exactly as in the original, and provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions, except that this permission notice may be stated in a
translation approved by the Free Software Foundation.
File: emacs-lisp-intro.info, Node: re-search-forward, Next: forward-sentence, Prev: sentence-end, Up: Regexp Search
The `re-search-forward' Function
================================
The `re-search-forward' function is very like the `search-forward'
function. (*Note The `search-forward' Function: search-forward.)
`re-search-forward' searches for a regular expression. If the
search is successful, it leaves point immediately after the last
character in the target. If the search is backwards, it leaves point
just before the first character in the target. You may tell
`re-search-forward' to return `t' for true. (Moving point is therefore
a `side effect'.)
Like `search-forward', the `re-search-forward' function takes four
arguments:
1. The first argument is the regular expression that the function
searches for. The regular expression will be a string between
quotations marks.
2. The optional second argument limits how far the function will
search; it is a bound, specified as a position in the buffer.
3. The optional third argument specifies how the function responds to
failure: `nil' as the third argument causes the function to signal
an error (and print a message) when the search fails; any other
value causes it to return `nil' if the search fails and `t' if the
search succeeds.
4. The optional fourth argument is the repeat count. A negative
repeat count causes `re-search-forward' to search backwards.
The template for `re-search-forward' looks like this:
(re-search-forward "REGULAR-EXPRESSION"
LIMIT-OF-SEARCH
WHAT-TO-DO-IF-SEARCH-FAILS
REPEAT-COUNT)
The second, third, and fourth arguments are optional. However, if
you want to pass a value to either or both of the last two arguments,
you must also pass a value to all the preceding arguments. Otherwise,
the Lisp interpreter will mistake which argument you are passing the
value to.
In the `forward-sentence' function, the regular expression will be
the value of the variable `sentence-end', namely:
"[.?!][]\"')}]*\\($\\| \\| \\)[
]*"
The limit of the search will be the end of the paragraph (since a
sentence cannot go beyond a paragraph). If the search fails, the
function will return `nil'; and the repeat count will be provided by
the argument to the `forward-sentence' function.
File: emacs-lisp-intro.info, Node: forward-sentence, Next: forward-paragraph, Prev: re-search-forward, Up: Regexp Search
`forward-sentence'
==================
The command to move the cursor forward a sentence is a
straightforward illustration of how to use regular expression searches
in Emacs Lisp. Indeed, the function looks longer and more complicated
than it is; this is because the function is designed to go backwards as
well as forwards; and, optionally, over more than one sentence. The
function is usually bound to the key command `M-e'.
Here is the code for `forward-sentence':
(defun forward-sentence (&optional arg)
"Move forward to next sentence-end. With argument, repeat.
With negative argument, move backward repeatedly to sentence-beginning.
Sentence ends are identified by the value of sentence-end
treated as a regular expression. Also, every paragraph boundary
terminates sentences as well."
(interactive "p")
(or arg (setq arg 1))
(while (< arg 0)
(let ((par-beg
(save-excursion (start-of-paragraph-text) (point))))
(if (re-search-backward
(concat sentence-end "[^ \t\n]") par-beg t)
(goto-char (1- (match-end 0)))
(goto-char par-beg)))
(setq arg (1+ arg)))
(while (> arg 0)
(let ((par-end
(save-excursion (end-of-paragraph-text) (point))))
(if (re-search-forward sentence-end par-end t)
(skip-chars-backward " \t\n")
(goto-char par-end)))
(setq arg (1- arg))))
The function looks long at first sight and it is best to look at its
skeleton first, and then its muscle. The way to see the skeleton is to
look at the expressions that start in the left-most columns:
(defun forward-sentence (&optional arg)
"DOCUMENTATION..."
(interactive "p")
(or arg (setq arg 1))
(while (< arg 0)
BODY-OF-WHILE-LOOP
(while (> arg 0)
BODY-OF-WHILE-LOOP
This looks much simpler! The function definition consists of
documentation, an `interactive' expression, an `or' expression, and
`while' loops.
Let's look at each of these parts in turn.
We note that the documentation is thorough and understandable.
The function has an `interactive "p"' declaration. This means that
the processed prefix argument, if any, is passed to the function as its
argument. (This will be a number.) If the function is not passed an
argument (it is optional) then the argument `arg' will be bound to 1.
When `forward-sentence' is called non-interactively without an
argument, `arg' is bound to `nil'.
The `or' expression handles the prefix argument. What it does is
either leave the value of `arg' as it is, but only if `arg' is bound to
a value; or it sets the value of `arg' to 1, in the case when `arg' is
bound to `nil'.
* Menu:
* fwd-sentence while loops:: Two `while' loops.
* fwd-sentence re-search:: A regular expression search.
File: emacs-lisp-intro.info, Node: fwd-sentence while loops, Next: fwd-sentence re-search, Prev: forward-sentence, Up: forward-sentence
The `while' loops
.................
Two `while' loops follow the `or' expression. The first `while' has
a true-or-false-test that tests true if the prefix argument for
`forward-sentence' is a negative number. This is for going backwards.
The body of this loop is similar to the body of the second `while'
clause, but it is not exactly the same. We will skip this `while' loop
and concentrate on the second `while' loop.
The second `while' loop is for moving point forward. Its skeleton
looks like this:
(while (> arg 0) ; true-or-false-test
(let VARLIST
(if (TRUE-OR-FALSE-TEST)
THEN-PART
ELSE-PART
(setq arg (1- arg)))) ; `while' loop decrementer
The `while' loop is of the decrementing kind. (*Note A Loop with a
Decrementing Counter: Decrementing Loop.) It has a true-or-false-test
that tests true so long as the counter (in this case, the variable
`arg') is greater than zero; and it has a decrementer that subtracts 1
from the value of the counter every time the loop repeats.
If no prefix argument is given to `forward-sentence', which is the
most common way the command is used, this `while' loop will run once,
since the value of `arg' will be 1.
The body of the `while' loop consists of a `let' expression, which
creates and binds a local variable, and has, as its body, an `if'
expression.
The body of the `while' loop looks like this:
(let ((par-end
(save-excursion (end-of-paragraph-text) (point))))
(if (re-search-forward sentence-end par-end t)
(skip-chars-backward " \t\n")
(goto-char par-end)))
The `let' expression creates and binds the local variable `par-end'.
As we shall see, this local variable is designed to provide a bound or
limit to the regular expression search. If the search fails to find a
proper sentence ending in the paragraph, it will stop on reaching the
end of the paragraph.
But first, let us examine how `par-end' is bound to the value of the
end of the paragraph. What happens is that the `let' sets the value of
`par-end' to the value returned when the Lisp interpreter evaluates the
expression
(save-excursion (end-of-paragraph-text) (point))
In this expression, `(end-of-paragraph-text)' moves point to the end of
the paragraph, `(point)' returns the value of point, and then
`save-excursion' restores point to its original position. Thus, the
`let' binds `par-end' to the value returned by the `save-excursion'
expression, which is the position of the end of the paragraph. (The
`(end-of-paragraph-text)' function uses `forward-paragraph', which we
will discuss shortly.)
Emacs next evaluates the body of the `let', which is an `if'
expression that looks like this:
(if (re-search-forward sentence-end par-end t) ; if-part
(skip-chars-backward " \t\n") ; then-part
(goto-char par-end))) ; else-part
The `if' tests whether its first argument is true and if so,
evaluates its then-part; otherwise, the Emacs Lisp interpreter
evaluates the else-part. The true-or-false-test of the `if' expression
is the regular expression search.
It may seem odd to have what looks like the `real work' of the
`forward-sentence' function buried here, but this is a common way this
kind of operation is carried out in Lisp.
File: emacs-lisp-intro.info, Node: fwd-sentence re-search, Prev: fwd-sentence while loops, Up: forward-sentence
The regular expression search
.............................
The `re-search-forward' function searches for the end of the
sentence, that is, for the pattern defined by the `sentence-end'
regular expression. If the pattern is found--if the end of the
sentence is found--then the `re-search-forward' function does two
things:
1. The `re-search-forward' function carries out a side effect, which
is to move point to the end of the occurrence found.
2. The `re-search-forward' function returns a value of true. This is
the value received by the `if', and means that the search was
successful.
The side effect, the movement of point, is completed before the `if'
function is handed the value returned by the successful conclusion of
the search.
When the `if' function receives the value of true from a successful
call to `re-search-forward', the `if' evaluates the then-part, which is
the expression `(skip-chars-backward " \t\n")'. This expression moves
backwards over any blank spaces, tabs or carriage returns until a
printed character is found and then leaves point after the character.
Since point has already been moved to the end of the pattern that marks
the end of the sentence, this action leaves point right after the
closing printed character of the sentence, which is usually a period.
On the other hand, if the `re-search-forward' function fails to find
a pattern marking the end of the sentence, the function returns false.
The false then causes the `if' to evaluate its third argument, which is
`(goto-char par-end)': it moves point to the end of the paragraph.
Regular expression searches are exceptionally useful and the pattern
illustrated by `re-search-forward', in which the search is the test of
an `if' expression, is handy. You will see or write code incorporating
this pattern often.
File: emacs-lisp-intro.info, Node: forward-paragraph, Next: etags, Prev: forward-sentence, Up: Regexp Search
`forward-paragraph': a Goldmine of Functions
============================================
The `forward-paragraph' function moves point forward to the end of
the paragraph. It is usually bound to `M-}' and makes use of a number
of functions that are important in themselves, including `let*',
`match-beginning', and `looking-at'.
The function definition for `forward-paragraph' is considerably
longer than the function definition for `forward-sentence' because it
works with a paragraph, each line of which may begin with a fill prefix.
A fill prefix consists of a string of characters that are repeated at
the beginning of each line. For example, in Lisp code, it is a
convention to start each line of a paragraph-long comment with `;;; '.
In Text mode, four blank spaces make up another common fill prefix,
creating an indented paragraph. (*Note Fill Prefix: (emacs)Fill
Prefix, for more information about fill prefixes.)
The existence of a fill prefix means that in addition to being able
to find the end of a paragraph whose lines begin on the left-most
column, the `forward-paragraph' function must be able to find the end
of a paragraph when all or many of the lines in the buffer begin with
the fill prefix.
Moreover, it is sometimes practical to ignore a fill prefix that
exists, especially when blank lines separate paragraphs. This is an
added complication.
Rather than print all of the `forward-paragraph' function, we will
only print parts of it. Read without preparation, the function can be
daunting!
In outline, the function looks like this:
(defun forward-paragraph (&optional arg)
"DOCUMENTATION..."
(interactive "p")
(or arg (setq arg 1))
(let*
VARLIST
(while (< arg 0) ; backward-moving-code
...
(setq arg (1+ arg)))
(while (> arg 0) ; forward-moving-code
...
(setq arg (1- arg)))))
The first parts of the function are routine: the function's argument
list consists of one optional argument. Documentation follows.
The lower case `p' in the `interactive' declaration means that the
processed prefix argument, if any, is passed to the function. This
will be a number, and is the repeat count of how many paragraphs point
will move. The `or' expression in the next line handles the common
case when no argument is passed to the function, which occurs if the
function is called from other code rather than interactively. This
case was described earlier. (*Note The `forward-sentence' function:
forward-sentence.) Now we reach the end of the familiar part of this
function.
* Menu:
* fwd-para let:: The `let*' expression.
* fwd-para while:: The forward motion `while' loop.
* fwd-para between paragraphs:: Movement between paragraphs.
* fwd-para within paragraph:: Movement within paragraphs.
* fwd-para no fill prefix:: When there is no fill prefix.
* fwd-para with fill prefix:: When there is a fill prefix.
* fwd-para summary:: Summary of `forward-paragraph' code.
File: emacs-lisp-intro.info, Node: fwd-para let, Next: fwd-para while, Prev: forward-paragraph, Up: forward-paragraph
The `let*' expression
.....................
The next line of the `forward-paragraph' function begins a `let*'
expression. This is a different kind of expression than we have seen
so far. The symbol is `let*' not `let'.
The `let*' special form is like `let' except that Emacs sets each
variable in sequence, one after another, and variables in the latter
part of the varlist can make use of the values to which Emacs set
variables in the earlier part of the varlist.
In the `let*' expression in this function, Emacs binds two
variables: `fill-prefix-regexp' and `paragraph-separate'. The value to
which `paragraph-separate' is bound depends on the value of
`fill-prefix-regexp'.
Let's look at each in turn. The symbol `fill-prefix-regexp' is set
to the value returned by evaluating the following list:
(and fill-prefix
(not (equal fill-prefix ""))
(not paragraph-ignore-fill-prefix)
(regexp-quote fill-prefix))
This is an expression whose first element is the function `and'.
The `and' function evaluates each of its arguments until one of the
arguments returns a value of `nil', in which case the `and' expression
returns `nil'; however, if none of the arguments returns a value of
`nil', the value resulting from evaluating the last argument is
returned. (Since such a value is not `nil', it is considered true in
Lisp.) In other words, an `and' expression returns a true value only
if all its arguments are true.
In this case, the variable `fill-prefix-regexp' is bound to a
non-`nil' value only if the following four expressions produce a true
(i.e., a non-`nil') value when they are evaluated; otherwise,
`fill-prefix-regexp' is bound to `nil'.
`fill-prefix'
When this variable is evaluated, the value of the fill prefix, if
any, is returned. If there is no fill prefix, this variable
returns `nil'.
`(not (equal fill-prefix "")'
This expression checks whether an existing fill prefix is an empty
string, that is, a string with no characters in it. An empty
string is not a useful fill prefix.
`(not paragraph-ignore-fill-prefix)'
This expression returns `nil' if the variable
`paragraph-ignore-fill-prefix' has been turned on by being set to a
true value such as `t'.
`(regexp-quote fill-prefix)'
This is the last argument to the `and' function. If all the
arguments to the `and' are true, the value resulting from
evaluating this expression will be returned by the `and' expression
and bound to the variable `fill-prefix-regexp',
The result of evaluating this `and' expression successfully is that
`fill-prefix-regexp' will be bound to the value of `fill-prefix' as
modified by the `regexp-quote' function. What `regexp-quote' does is
read a string and return a regular expression that will exactly match
the string and match nothing else. This means that
`fill-prefix-regexp' will be set to a value that will exactly match the
fill prefix if the fill prefix exists. Otherwise, the variable will be
set to `nil'.
The second local variable in the `let*' expression is
`paragraph-separate'. It is bound to the value returned by evaluating
the expression:
(if fill-prefix-regexp
(concat paragraph-separate
"\\|^" fill-prefix-regexp "[ \t]*$")
paragraph-separate)))
This expression shows why `let*' rather than `let' was used. The
true-or-false-test for the `if' depends on whether the variable
`fill-prefix-regexp' evaluates to `nil' or some other value.
If `fill-prefix-regexp' does not have a value, Emacs evaluates the
else-part of the `if' expression and binds `paragraph-separate' to its
local value. (`paragraph-separate' is a regular expression that
matches what separates paragraphs.)
But if `fill-prefix-regexp' does have a value, Emacs evaluates the
then-part of the `if' expression and binds `paragraph-separate' to a
regular expression that includes the `fill-prefix-regexp' as part of
the pattern.
Specifically, `paragraph-separate' is set to the original value of
the paragraph separate regular expression concatenated with an
alternative expression that consists of the `fill-prefix-regexp'
followed by a blank line. The `^' indicates that the
`fill-prefix-regexp' must begin a line, and the optional whitespace to
the end of the line is defined by `"[ \t]*$"'.) The `\\|' defines this
portion of the regexp as an alternative to `paragraph-separate'.
Now we get into the body of the `let*'. The first part of the body
of the `let*' deals with the case when the function is given a negative
argument and is therefore moving backwards. We will skip this section.
File: emacs-lisp-intro.info, Node: fwd-para while, Next: fwd-para between paragraphs, Prev: fwd-para let, Up: forward-paragraph
The forward motion `while' loop
...............................
The second part of the body of the `let*' deals with forward motion.
It is a `while' loop that repeats itself so long as the value of `arg'
is greater than zero. In the most common use of the function, the
value of the argument is 1, so the body of the `while' loop is
evaluated exactly once, and the cursor moves forward one paragraph.
This part handles three situations: when point is between paragraphs,
when point is within a paragraph and there is a fill prefix, and when
point is within a paragraph and there is no fill prefix.
The `while' loop looks like this:
(while (> arg 0)
(beginning-of-line)
;; between paragraphs
(while (prog1 (and (not (eobp))
(looking-at paragraph-separate))
(forward-line 1)))
;; within paragraphs, with a fill prefix
(if fill-prefix-regexp
;; There is a fill prefix; it overrides paragraph-start.
(while (and (not (eobp))
(not (looking-at paragraph-separate))
(looking-at fill-prefix-regexp))
(forward-line 1))
;; within paragraphs, no fill prefix
(if (re-search-forward paragraph-start nil t)
(goto-char (match-beginning 0))
(goto-char (point-max))))
(setq arg (1- arg)))
We can see immediately that this is a decrementing counter `while'
loop, using the expression `(setq (1- arg))' as the decrementer. The
body of the loop consists of three expressions:
;; between paragraphs
(beginning-of-line)
(while
BODY-OF-WHILE)
;; within paragraphs, with fill prefix
(if TRUE-OR-FALSE-TEST
THEN-PART
;; within paragraphs, no fill prefix
ELSE-PART
When the Emacs Lisp interpreter evaluates the body of the `while' loop,
the first thing it does is evaluate the `(beginning-of-line)'
expression and move point to the beginning of the line. Then there is
an inner `while' loop. This `while' loop is designed to move the
cursor out of the blank space between paragraphs, if it should happen
to be there. Finally there is an `if' expression that actually moves
point to the end of the paragraph.
File: emacs-lisp-intro.info, Node: fwd-para between paragraphs, Next: fwd-para within paragraph, Prev: fwd-para while, Up: forward-paragraph
Between paragraphs
..................
First, let us look at the inner `while' loop. This loop handles the
case when point is between paragraphs; it uses three functions that are
new to us: `prog1', `eobp' and `looking-at'.
* `prog1' is similar to the `progn' function, except that `prog1'
evaluates its arguments in sequence and then returns the value of
its first argument as the value of the whole expression. (`progn'
returns the value of its last argument as the value of the
expression.) The second and subsequent arguments to `prog1' are
evaluated only for their side effects.
* `eobp' is an abbreviation of `End Of Buffer P' and is a function
that returns true if point is at the end of the buffer.
* `looking-at' is a function that returns true if the text following
point matches the regular expression passed `looking-at' as its
argument.
The `while' loop we are studying looks like this:
(while (prog1 (and (not (eobp))
(looking-at paragraph-separate))
(forward-line 1)))
This is a `while' loop with no body! The true-or-false-test of the
loop is the expression:
(prog1 (and (not (eobp))
(looking-at paragraph-separate))
(forward-line 1)))
The first argument to the `prog1' is the `and' expression. It has
within in it a test of whether point is at the end of the buffer and
also a test of whether the pattern following point matches the regular
expression for separating paragraphs.
If the cursor is not at the end of the buffer and if the characters
following the cursor mark the separation between two paragraphs, then
the `and' expression is true. After evaluating the `and' expression,
the Lisp interpreter evaluates the second argument to `prog1', which is
`forward-line'. This moves point forward one line. The value returned
by the `prog1' however, is the value of its first argument, so the
`while' loop continues so long as point is not at the end of the buffer
and is between paragraphs. When, finally, point is moved to a
paragraph, the `and' expression tests false. Note however, that the
`forward-line' command is carried out anyhow. This means that when
point is moved from between paragraphs to a paragraph, it is left at
the beginning of the second line of the paragraph.
File: emacs-lisp-intro.info, Node: fwd-para within paragraph, Next: fwd-para no fill prefix, Prev: fwd-para between paragraphs, Up: forward-paragraph
Within paragraphs
.................
The next expression in the outer `while' loop is an `if' expression.
The Lisp interpreter evaluates the then-part of the `if' when the
`fill-prefix-regexp' variable has a value other than `nil', and it
evaluates the else-part when the value of `if fill-prefix-regexp' is
`nil', that is, when there is no fill prefix.
File: emacs-lisp-intro.info, Node: fwd-para no fill prefix, Next: fwd-para with fill prefix, Prev: fwd-para within paragraph, Up: forward-paragraph
No fill prefix
..............
It is simplest to look at the code for the case when there is no fill
prefix first. This code consists of yet another inner `if' expression,
and reads as follows:
(if (re-search-forward paragraph-start nil t)
(goto-char (match-beginning 0))
(goto-char (point-max)))
This expression actually does the work that most people think of as the
primary purpose of the `forward-paragraph' command: it causes a regular
expression search to occur that searches forward to the start of the
next paragraph and if it is found, moves point there; but if the start
of another paragraph if not found, it moves point to the end of the
accessible region of the buffer.
The only unfamiliar part of this is the use of `match-beginning'.
This is another function that is new to us. The `match-beginning'
function returns a number specifying the location of the start of the
text that was matched by the last regular expression search.
The `match-beginning' function is used here because of a
characteristic of a forward search: a successful forward search,
regardless of whether it is a plain search or a regular expression
search, will move point to the end of the text that is found. In this
case, a successful search will move point to the end of the pattern for
`paragraph-start', which will be the beginning of the next paragraph
rather than the end of the current one.
However, we want to put point at the end of the current paragraph,
not at the beginning of the next one. The two positions may be
different, because there may be several blank lines between paragraphs.
When given an argument of 0, `match-beginning' returns the position
that is the start of the text that the most recent regular expression
search matched. In this case, the most recent regular expression
search is the one looking for `paragraph-start', so `match-beginning'
returns the beginning position of the pattern, rather than the end of
the pattern. The beginning position is the end of the paragraph.
(Incidentally, when passed a positive number as an argument, the
`match-beginning' function will place point at that parenthesized
expression in the last regular expression. It is a useful function.)
File: emacs-lisp-intro.info, Node: fwd-para with fill prefix, Next: fwd-para summary, Prev: fwd-para no fill prefix, Up: forward-paragraph
With a fill prefix
..................
The inner `if' expression just discussed is the else-part of an
enclosing `if' expression which tests whether there is a fill prefix.
If there is a fill prefix, the then-part of this `if' is evaluated. It
looks like this:
(while (and (not (eobp))
(not (looking-at paragraph-separate))
(looking-at fill-prefix-regexp))
(forward-line 1))
What this expression does is move point forward line by line so long as
three conditions are true:
1. Point is not at the end of the buffer.
2. The text following point does not separate paragraphs.
3. The pattern following point is the fill prefix regular expression.
The last condition may be puzzling, until you remember that point was
moved to the beginning of the line early in the `forward-paragraph'
function. This means that if the text has a fill prefix, the
`looking-at' function will see it.
File: emacs-lisp-intro.info, Node: fwd-para summary, Prev: fwd-para with fill prefix, Up: forward-paragraph
Summary
.......
In summary, when moving forward, the `forward-paragraph' function
does the following:
* Move point to the beginning of the line.
* Skip over lines between paragraphs.
* Check whether there is a fill prefix, and if there is:
-- Go forward line by line so long as the line is not a
paragraph separating line.
* But if there is no fill prefix,
-- Search for the next paragraph start pattern.
-- Go to the beginning of the paragraph start pattern, which
will be the end of the previous paragraph.
-- Or else go to the end of the accessible portion of the
buffer.
For review, here is the code we have just been discussing, formatted
for clarity:
(interactive "p")
(or arg (setq arg 1))
(let* (
(fill-prefix-regexp
(and fill-prefix (not (equal fill-prefix ""))
(not paragraph-ignore-fill-prefix)
(regexp-quote fill-prefix)))
(paragraph-separate
(if fill-prefix-regexp
(concat paragraph-separate
"\\|^"
fill-prefix-regexp
"[ \t]*$")
paragraph-separate)))
BACKWARD-MOVING-CODE (OMITTED) ...
(while (> arg 0) ; forward-moving-code
(beginning-of-line)
(while (prog1 (and (not (eobp))
(looking-at paragraph-separate))
(forward-line 1)))
(if fill-prefix-regexp
(while (and (not (eobp)) ; then-part
(not (looking-at paragraph-separate))
(looking-at fill-prefix-regexp))
(forward-line 1))
; else-part: the inner-if
(if (re-search-forward paragraph-start nil t)
(goto-char (match-beginning 0))
(goto-char (point-max))))
(setq arg (1- arg))))) ; decrementer
The full definition for the `forward-paragraph' function not only
includes this code for going forwards, but also code for going
backwards.
If you are reading this inside of GNU Emacs and you want to see the
whole function, you can type `M-.' (`find-tag') and the name of the
function when prompted for it. If the `find-tag' function first asks
you for the name of a `TAGS' table, give it the name of the `TAGS' file
in your `emacs/src' directory, which will have a pathname such as
`/usr/local/lib/emacs/19.23/src/TAGS'. (The exact path to the
`emacs/src' directory depends on how your copy of Emacs was installed.
If you don't know the path, you can sometimes find out by typing `C-h
i' to enter Info and then typing `C-x C-f' to see the path to the
`emacs/info' directory. The path to the `TAGS' file is often the
corresponding `emacs/src' path; sometimes, however, Info files are
stored elsewhere.)
You can also create your own `TAGS' file for directories that lack
one. *Note Create Your Own `TAGS' File: etags.
File: emacs-lisp-intro.info, Node: etags, Next: Regexp Review, Prev: forward-paragraph, Up: Regexp Search
Create Your Own `TAGS' File
===========================
You can create your own `TAGS' file to help you jump to sources.
For example, if you have a large number of files in your `~/emacs'
directory, as I do--I have 137 `.el' files in it, of which I load 17--
you will find it easier to jump to specific functions if you create a
`TAGS' file for that directory than if you search for the function name
with `grep' or some other tool.
You can create a `TAGS' file by calling the `etags' program that
comes as a part of the Emacs distribution. Usually, `etags' is
compiled and installed when Emacs is built. (`etags' is not an Emacs
Lisp function or a part of Emacs; it is a C program.)
To create a `TAGS' file, first switch to the directory in which you
want to create the file. In Emacs you can do this with the `M-x cd'
command, or by visiting a file in the directory, or by listing the
directory with `C-x d' (`dired'). Then type
M-! etags *.el
to create a `TAGS' file. The `etags' program takes all the usual shell
`wildcards'. For example, if you have two directories for which you
want a single `TAGS file', type the command like this, where
`../elisp/' is the second directory:
M-! etags *.el ../elisp/*.el
Type
M-! etags --help
to see a list of the options accepted by `etags'.
The `etags' program handles Emacs Lisp, Common Lisp, Scheme, C,
Fortran, Pascal, LaTeX, and most assemblers. The program has no
switches for specifying the language; it recognizes the language in an
input file according to its file name and contents.
Also, `etags' is very helpful when you are writing code yourself and
want to refer back to functions you have already written. Just run
`etags' again at intervals as you write new functions, so they become
part of the `TAGS' file.
File: emacs-lisp-intro.info, Node: Regexp Review, Next: re-search Exercises, Prev: etags, Up: Regexp Search
Review
======
Here is a brief summary of some recently introduced functions.
`while'
Repeatedly evaluate the body of the expression so long as the first
element of the body tests true. Then return `nil'. (The
expression is evaluated only for its side effects.)
For example:
(let ((foo 2))
(while (> foo 0)
(insert (format "foo is %d.\n" foo))
(setq foo (1- foo))))
=> foo is 2.
foo is 1.
nil
(The `insert' function inserts its arguments at point; the
`format' function returns a string formatted from its arguments
the way `message' formats its arguments; `\n' produces a new line.)
`re-search-forward'
Search for a pattern, and if the pattern is found, move point to
rest just after it.
Takes four arguments, like `search-forward':
1. A regular expression that specifies the pattern to search for.
2. Optionally, the limit of the search.
3. Optionally, what to do if the search fails, return `nil' or an
error message.
4. Optionally, how many times to repeat the search; if negative,
the search goes backwards.
`let*'
Bind some variables locally to particular values, and then
evaluate the remaining arguments, returning the value of the last
one. While binding the local variables, use the local values of
variables bound earlier, if any.
For example:
(let* ((foo 7)
(bar (* 3 foo)))
(message "`bar' is %d." bar))
=> `bar' is 21.
`match-beginning'
Return the position of the start of the text found by the last
regular expression search.
`looking-at'
Return `t' for true if the text after point matches the argument,
which should be a regular expression.
`eobp'
Return `t' for true if point is at the end of the accessible part
of a buffer. The end of the accessible part is the end of the
buffer if the buffer is not narrowed; it is the end of the
narrowed part if the buffer is narrowed.
`prog1'
Evaluate each argument in sequence and then return the value of the
*first*.
For example:
(prog1 1 2 3 4)
=> 1
File: emacs-lisp-intro.info, Node: re-search Exercises, Prev: Regexp Review, Up: Regexp Search
Exercises with `re-search-forward'
==================================
* Write a function to search for a regular expression that matches
two or more blank lines in sequence.
* Write a function to search for duplicated words, such as `the the'.
*Note Syntax of Regular Expressions: (emacs)Regexps, for
information on how to write a regexp (a regular expression) to
match a string that is composed of two identical halves. You can
devise several regexps; some are better than others. The function
I use is described in an appendix, along with several regexps.
*Note `the-the' Duplicated Words Function: the-the.
File: emacs-lisp-intro.info, Node: Counting Words, Next: Words in a defun, Prev: Regexp Search, Up: Top
Counting: Repetition and Regexps
********************************
Repetition and regular expression searches are powerful tools that
you often use when you write code in Emacs Lisp. This chapter
illustrates the use of regular expression searches through the
construction of word count commands using `while' loops and recursion.
* Menu:
* Why Count Words:: Emacs lacks a word count command.
* count-words-region:: Use a regexp, but find a problem.
* recursive-count-words:: Start with case of no words in region.
* Counting Exercise::
File: emacs-lisp-intro.info, Node: Why Count Words, Next: count-words-region, Prev: Counting Words, Up: Counting Words
Counting words
==============
The standard Emacs distribution contains a function for counting the
number of lines within a region. However, there is no corresponding
function for counting words.
Certain types of writing ask you to count words. Thus, if you write
an essay, you may be limited to 800 words; if you write a novel, you
may discipline yourself to write 1000 words a day. It seems odd to me
that Emacs lacks a word count command. Perhaps people use Emacs mostly
for code or types of documentation that do not require word counts; or
perhaps they restrict themselves to the operating system word count
command, `wc'. Alternatively, people may follow the publishers'
convention and compute a word count by dividing the number of
characters in a document by five. In any event, here are commands to
count words.
File: emacs-lisp-intro.info, Node: count-words-region, Next: recursive-count-words, Prev: Why Count Words, Up: Counting Words
The `count-words-region' Function
=================================
A word count command could count words in a line, paragraph, region,
or buffer. What should the command cover? You could design the
command to count the number of words in a complete buffer. However,
the Emacs tradition encourages flexibility--you may want to count words
in just a section, rather than all of a buffer. So it makes more sense
to design the command to count the number of words in a region. Once
you have a `count-words-region' command, you can, if you wish, count
words in a whole buffer by marking it with `C-x h'
(`mark-whole-buffer').
Clearly, counting words is a repetitive act: starting from the
beginning of the region, you count the first word, then the second
word, then the third word, and so on, until you reach the end of the
region. This means that word counting is ideally suited to recursion
or to a `while' loop.
First, we will implement the word count command with a `while' loop,
then with recursion. The command will, of course, be interactive.
The template for an interactive function definition is, as always:
(defun NAME-OF-FUNCTION (ARGUMENT-LIST)
"DOCUMENTATION..."
(INTERACTIVE-EXPRESSION...)
BODY...)
What we need to do is fill in the slots.
The name of the function should be self-explanatory and similar to
the existing `count-lines-region' name. This makes the name easier to
remember. `count-words-region' is a good choice.
The function counts words within a region. This means that the
argument list must contain symbols that are bound to the two positions,
the beginning and end of the region. These two positions can be called
`beginning' and `end' respectively. The first line of the
documentation should be a single sentence, since that is all that is
printed as documentation by a command such as `apropos'. The
interactive expression will be of the form `(interactive "r")', since
that will cause Emacs to pass the beginning and end of the region to
the function's argument list. All this is routine.
The body of the function needs to be written so as to do three tasks:
first to set up conditions under which the `while' loop can count words,
second to run the `while' loop, and, third, to send a message to the
user.
When a user calls `count-words-region', point may be at the
beginning or the end of the region. However, the counting process must
start at the beginning of the region. This means we will want to put
point there if it is not already there. Executing `(goto-char
beginning)' ensures this. Of course, we will want to return point to
its expected position when the function finishes its work. For this
reason, the body must be enclosed in a `save-excursion' expression.
The central part of the body of the function consists of a `while'
loop in which one expression jumps point forward word by word, and
another expression counts those jumps. The true-or-false-test of the
`while' loop should test true so long as point should jump forward, and
false when point is at the end of the region.
We could use `(forward-word 1)' as the expression for moving point
forward word by word, but it is easier to see what Emacs identifies as a
`word' if we use a regular expression search.
A regular expression search that finds the pattern for which it is
searching leaves point after the last character matched. This means
that a succession of successful word searches will move point forward
word by word.
As a practical matter, we want the regular expression search to jump
over whitespace and punctuation between words as well as over the words
themselves. A regexp that refuses to jump over interword whitespace
would never jump more than one word! This means that the regexp should
include the whitespace and punctuation that follows a word, if any, as
well as the word itself. (A word may end a buffer and not have any
following whitespace or punctuation, so that part of the regexp must be
optional.)
Thus, what we want for the regexp is a pattern defining one or more
word constituent characters followed, optionally, by one or more
characters that are not word constituents. The regular expression for
this is:
\w+\W*
The buffer's syntax table determines which characters are and are not
word constituents. (*Note What Constitutes a Word or Symbol?: Syntax,
for more about syntax. Also, see *Note Syntax: (emacs)Syntax, and,
*Note Syntax Tables: (elisp)Syntax Tables.)
The search expression looks like this:
(re-search-forward "\\w+\\W*")
(Note that paired backslashes precede the `w' and `W'. A single
backslash has special meaning to the Emacs Lisp interpreter. It
indicates that the following character is interpreted differently than
usual. For example, the two characters, `\n', stand for `newline',
rather than for a backslash followed by `n'. Two backslashes in a row
stand for an ordinary, `unspecial' backslash.)
We need a counter to count how many words there are; this variable
must first be set to 0 and then incremented each time Emacs goes around
the `while' loop. The incrementing expression is simply:
(setq count (1+ count))
Finally, we want to tell the user how many words there are in the
region. The `message' function is intended for presenting this kind of
information to the user. The message has to be phrased so that it
reads properly regardless of how many words there are in the region: we
don't want to say that "there are 1 words in the region". The conflict
between singular and plural is ungrammmatical. We can solve this
problem by using a conditional expression that evaluates different
messages depending on the number of words in the region. There are
three possibilities: no words in the region, one word in the region,
and more than one word. This means that the `cond' special form is
appropriate.
All this leads to the following function definition:
;;; First version; has bugs!
(defun count-words-region (beginning end)
"Print number of words in the region.
Words are defined as at least one word-constituent
character followed by at least one character that
is not a word-constituent. The buffer's syntax
table determines which characters these are."
(interactive "r")
(message "Counting words in region ... ")
;;; 1. Set up appropriate conditions.
(save-excursion
(goto-char beginning)
(let ((count 0))
;;; 2. Run the while loop.
(while (< (point) end)
(re-search-forward "\\w+\\W*")
(setq count (1+ count)))
;;; 3. Send a message to the user.
(cond ((zerop count)
(message
"The region does NOT have any words."))
((= 1 count)
(message
"The region has 1 word."))
(t
(message
"The region has %d words." count))))))
As written, the function works, but not in all circumstances.
* Menu:
* Whitespace Bug:: The Whitespace Bug in `count-words-region'